#include "jabstractio.h"
#include "jabstractio_p.h"

namespace JXQ
{

JAbstractIOPrivate::JAbstractIOPrivate(JAbstractIO *q_ptr) :
	q_ptr(q_ptr)
{

}

JAbstractIOPrivate::~JAbstractIOPrivate()
{

}

bool JAbstractIOPrivate::check(OpenMode mode) const
{
	if( not m_isOpen )
	{
		q_ptr->setErrno(IsNotOpen);
		return false;
	}

	if( not (m_openMode & mode) )
	{
		q_ptr->setErrno(NoPermissions);
		return false;
	}
	return true;
}

/*----------------------------------------------------------------------------------------------*/

JAbstractIO::JAbstractIO() :
	d_ptr(new JAbstractIOPrivate(this))
{

}

JAbstractIO::JAbstractIO(JAbstractIOPrivate *d_ptr) :
	d_ptr(d_ptr)
{

}

JAbstractIO::~JAbstractIO()
{
	delete d_ptr;
}

bool JAbstractIO::open(OpenMode mode)
{
	J_MUTEX_LOCKER(d_ptr->m_openMutex);
	setErrno(0);
	d_ptr->m_isOpen = true;
	d_ptr->m_openMode = mode;
	return true;
}

bool JAbstractIO::close()
{
	J_MUTEX_LOCKER(d_ptr->m_openMutex);
	setErrno(0);

	if( not d_ptr->m_isOpen )
		return false;

	if( d_ptr->m_isBusy )
	{
//		setErrno();
		return false;
	}

	flush();
	d_ptr->m_isOpen = false;
	d_ptr->m_openMode = JAbstractIO::NotOpen;
	return true;
}

bool JAbstractIO::isOpen() const
{
	return d_ptr->m_isOpen;
}

JAbstractIO::OpenMode JAbstractIO::openMode() const
{
	return d_ptr->m_openMode;
}

void JAbstractIO::setOpenMode(OpenMode mode, bool flag)
{
	J_MUTEX_LOCKER(d_ptr->m_openMutex);
	setErrno(0);

	if( flag )
		d_ptr->m_openMode |= mode;
	else
		d_ptr->m_openMode &= ~mode;
}

int64_t JAbstractIO::read(void *buffer, int64_t bufSize)
{
	return virtualRead(bufSize, buffer);
}

JString JAbstractIO::readLine()
{
	JString str("");
	char buffer = 0;

	for(;;)
	{
		int64_t res = read(&buffer, 1);
		if( res > 0 )
		{
			str += buffer;
			if( buffer == '\n' )
				break;
		}
		else
			break;
	}
	return str;
}

JString JAbstractIO::readAll()
{
#if 0
	if( d_ptr->check(ReadOnly) == false )
		return JString();

	auto size = this->size();
	char *buffer = new char[size + 1];
	read(size, buffer);

	JString tmp(buffer);
	delete[] buffer;
	return tmp;
#elif 0
	JString res;
	while(true)
	{
		char buf[1024] = "";
		int size = read(buf, 1023);
		if( size <= 0 )
			break;
		res += buf;
	}
	return res;
#else
	int64_t size = bytesAvailable();
	auto tmp = std::shared_ptr<char>(new char[size + 1]);
	memset(tmp.get(), 0, size+1);

	virtualRead(size, tmp.get());
	return JString(tmp.get());
#endif
}

int64_t JAbstractIO::write(const JString &buffer)
{
	return virtualWrite(buffer.size() + 1, buffer.c_str());
}

int64_t JAbstractIO::write(const char *buffer)
{
	return virtualWrite(strlen(buffer) + 1, buffer);
}

int64_t JAbstractIO::write(const void *buffer, int64_t bufSize)
{
	return virtualWrite(bufSize, buffer);
}

char JAbstractIO::getChar()
{
	char c = 0;
	getChar(c);
	return c;
}

bool JAbstractIO::getChar(char &c)
{
	return read(&c,1) == 1;
}

bool JAbstractIO::putChar(const char &c)
{
	return write(&c,1);
}

void JAbstractIO::setBufferMode(BufferMode mode)
{
	d_ptr->m_bufMode = mode;
//	if()
}

BufferMode JAbstractIO::bufferMode() const
{
	return d_ptr->m_bufMode;
}

void JAbstractIO::setBufferSize(int64_t)
{

}

void JAbstractIO::flush()
{

}

bool JAbstractIO::waitForReadyRead(int msecs)
{
	std::unique_lock<std::mutex> locker(d_ptr->m_readWaitMutex);

	if( msecs > 0 )
	{
		if( d_ptr->m_readCondition.wait_for(locker, std::chrono::milliseconds(msecs))
			== std::cv_status::timeout )
			return false;
	}
	else
		d_ptr->m_readCondition.wait(locker);

	return d_ptr->m_errNum==0? true : false;
}

void JAbstractIO::setErrno(int errNum)
{
	d_ptr->m_errNum = errNum;
}

int JAbstractIO::lastErrno() const
{
	return d_ptr->m_errNum;
}

inline JString JAbstractIO::lastError() const
{
	switch( d_ptr->m_errNum )
	{
		case NotOpen:        return "I/O is not open.";

		case NoExist:        return "File or device does not exist.";

		case NoPermissions : return "Permissions error.";

		case Busy:           return "Device is busy.";

		default: return "Unknown error.";
	}
}

} //namespace JXQ
